﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Text;
using StackExchange.Profiling;
using WebUI.Models;
using WebUI.Utils;
using WebUI.HtmlHelpers;
using Utils;
using ServiceStack.Text;

namespace WebUI.Controllers
{

    public abstract class BaseController : Controller
    {
        //this identity doesn't have UserName, only LoginID, AccountID, AccountType, NO DB query
        public UserIdentityModel IdentityWithoutUserName { 
            get { 
                return ViewModelUtils.CreateUserIdentityModel(false); 
            } 
        }
        //this identity has UserName,  HAS ONE DB query
        public UserIdentityModel IdentityWithUserName
        {
            get{
                return ViewModelUtils.CreateUserIdentityModel(true);
            }
        }

        protected string GetWebProjectPhysicalPath()
        {
            return Server.MapPath("~");
        }

        protected string RenderPartialViewToString()
        {
            return RenderPartialViewToString(null, null);
        }

        protected string RenderPartialViewToString(string viewName)
        {
            return RenderPartialViewToString(viewName, null);
        }

        protected string RenderPartialViewToString(object model)
        {
            return RenderPartialViewToString(null, model);
        }

        protected string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }

        protected string RenderViewToString(string viewName, object model, string masterName)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindView(ControllerContext, viewName, masterName);
                ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }

        /// <summary>
        /// Time Measurement
        /// </summary>
        /// <param name="filterContext"></param>        
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var profiler = MiniProfiler.Current;

            using (profiler.Step("OnActionExecuting"))
            {
                base.OnActionExecuting(filterContext);
            }
        }

        protected override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            _resultExecutingToExecuted = MiniProfiler.Current.Step("OnResultExecuting");

            base.OnResultExecuting(filterContext);
        }

        private IDisposable _resultExecutingToExecuted;

        protected override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            if (_resultExecutingToExecuted != null)
                _resultExecutingToExecuted.Dispose();

            base.OnResultExecuted(filterContext);
        }

        public string AbsoluteUrlForEmailConfirmation(string email, string key)
        {
            string absUrl = Url.ActionAbsolute("email_confirmation", "account", new {Email = HttpUtility.UrlEncode(email), Key = key });
            return absUrl;
        }

        public string AbsoluteUrlForPasswordReset(string email, string key)
        {
            string absUrl = Url.ActionAbsolute("ResetPassword", "account", new { Email = HttpUtility.UrlEncode(email), Key =  key});
            return absUrl;
        }

        public string GetFirstModelStateErrorMessage(ModelStateDictionary modelState)
        { 
            string message = string.Empty;
            foreach(var state in modelState.Values)
            {
                foreach(var error in state.Errors)
                {
                    if (!string.IsNullOrEmpty(error.ErrorMessage))
                    {
                        message = error.ErrorMessage;
                        return message;
                    }
                }
            }
            return message;
        }



        public void CreateSessionMessageForSuccess(string message)
        {
            TempData[ConstUtils.S_Notification_Success] = message;
        }

        public void CreateSessionMessageForError(string message)
        {
            TempData[ConstUtils.S_Notification_Error] = message;
        }

        public void CreateSessionForPreviousStepSuccess()
        {
            TempData[ConstUtils.S_PreviousStep_Success] = ConstUtils.V_Exists;
        }

        public Boolean SessionExistsForPreviousStepSuccess()
        {
            return TempData[ConstUtils.S_PreviousStep_Success] != null && (TempData[ConstUtils.S_PreviousStep_Success].ToString() == ConstUtils.V_Exists);
        }

        /// <summary>
        /// Add a cookie to cookie collection with an old date
        /// </summary>
        /// <param name="cookieName"></param>
        protected void DeleteCookie(string name)
        {
            HttpCookie cookie = new HttpCookie(name);
            cookie.Value = "Expired Cookie";
            cookie.HttpOnly = true;
            cookie.Expires = DateTime.Now.AddDays(-1);
            Response.Cookies.Add(cookie);
        }

        protected void CreateCookie(string name, string value, int expiresInDays = 90)
        {
            DeleteCookie(name);
            HttpCookie cookie = new HttpCookie(name);
            cookie.Value = value;
            cookie.HttpOnly = true;
            cookie.Expires = DateTime.Now.AddDays(expiresInDays);
            Response.Cookies.Add(cookie);
        }

        protected string GetCookieValue(string name)
        {
            if (Request.Cookies[name] != null)
            {
                if (!string.IsNullOrEmpty(Request.Cookies[name].Value))
                {
                    return Request.Cookies[name].Value;
                }
                else
                {
                    return string.Empty;
                }
            }
            else
            {
                return string.Empty;
            }
        }

        protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior)
        {
            //if data is JsonResultModel, for redirect, we need set up TempData
            if (data != null && data is JsonResultModel)
            {
                var temp = data as JsonResultModel;
                if (temp.Success == 1 && temp.ResultType == JsonResultType.SuccessWithRedirectUrlAndSummaryMessage)
                {
                    CreateSessionMessageForSuccess(temp.SummaryMessage);
                }
                else if (temp.Success == 0 && temp.ResultType == JsonResultType.ErrorWithRedirectUrlAndSummaryMessage)
                {
                    CreateSessionMessageForError(temp.SummaryMessage);
                }
            }
            //if data is upload image model, change the contentType, using text/html. Because if don't use this, for IE, Firefox 3.6 etc, It will download file.
            else if (data != null && data is JsonResultUploadFileModel)
            {
                contentType = !string.IsNullOrEmpty(contentType) ? contentType : "text/html";
                var temp = data as JsonResultUploadFileModel;
                if (temp.Success == 1 && temp.ResultType == JsonResultUploadFileType.SuccessWithRedirectUrlAndSummaryMessage)
                {
                    CreateSessionMessageForSuccess(temp.SummaryMessage);
                }
                else if (temp.Success == 0 && temp.ResultType == JsonResultUploadFileType.ErrorWithRedirectUrlAndSummaryMessage)
                {
                    CreateSessionMessageForError(temp.SummaryMessage);
                }
            }

            return new ServiceStackJsonResult
            {
                Data = data,
                ContentType = contentType,
                ContentEncoding = contentEncoding
            };
        }
    }

    public class ServiceStackJsonResult : JsonResult
    {
        public override void ExecuteResult(ControllerContext context)
        {
            var response = context.HttpContext.Response;
            response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";

            if (ContentEncoding != null)
            {
                response.ContentEncoding = ContentEncoding;
            }

            if (Data != null)
            {
                response.Write(JsonSerializer.SerializeToString(Data));
            }
        }
    }

}
